package net.esj.basic.core.view;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Pattern;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * HttpServletRequest帮助类
 * 
 * 
 */
public class RequestUtils {
    private static final Logger log   = LoggerFactory
                                                             .getLogger(RequestUtils.class);

    private static final String HEADER_IF_MODIFIED_SINCE = "If-Modified-Since";

    private static final String HEADER_LAST_MODIFIED     = "Last-Modified";

    /**
     * 获取QueryString的参数，并使用URLDecoder以UTF-8格式转码。
     * 
     * @param request
     *            web请求
     * @param name
     *            参数名称
     * @return
     */
    public static String getQueryParam(HttpServletRequest request, String name, String encoding) {
        String s = request.getQueryString();
        if (StringUtils.isBlank(s)) {
            return null;
        }
        try {
            s = URLDecoder.decode(s, encoding);
        } catch (UnsupportedEncodingException e) {
            log.error("encoding " + encoding + " not support.", e);
        }
        if (StringUtils.isBlank(s)) {
            return null;
        }
        String[] values = parseQueryString(s).get(name);
        if (values != null && values.length > 0) {
            return values[values.length - 1];
        } else {
            return null;
        }
    }

    /**
     * 
     * Parses a query string passed from the client to the server and builds a
     * <code>HashTable</code> object with key-value pairs. The query string
     * should be in the form of a string packaged by the GET or POST method,
     * that is, it should have key-value pairs in the form <i>key=value</i>,
     * with each pair separated from the next by a &amp; character.
     * 
     * <p>
     * A key can appear more than once in the query string with different
     * values. However, the key appears only once in the hashtable, with its
     * value being an array of strings containing the multiple values sent by
     * the query string.
     * 
     * <p>
     * The keys and values in the hashtable are stored in their decoded form, so
     * any + characters are converted to spaces, and characters sent in
     * hexadecimal notation (like <i>%xx</i>) are converted to ASCII characters.
     * 
     * @param s
     *            a string containing the query to be parsed
     * 
     * @return a <code>HashTable</code> object built from the parsed key-value
     *         pairs
     * 
     * @exception IllegalArgumentException
     *                if the query string is invalid
     * 
     */
    public static Map<String, String[]> parseQueryString(String s) {
        String valArray[] = null;
        if (s == null) {
            throw new IllegalArgumentException();
        }
        Map<String, String[]> ht = new HashMap<String, String[]>();
        StringTokenizer st = new StringTokenizer(s, "&");
        while (st.hasMoreTokens()) {
            String pair = (String) st.nextToken();
            int pos = pair.indexOf('=');
            if (pos == -1) {
                continue;
            }
            String key = pair.substring(0, pos);
            String val = pair.substring(pos + 1, pair.length());
            if (ht.containsKey(key)) {
                String oldVals[] = (String[]) ht.get(key);
                valArray = new String[oldVals.length + 1];
                for (int i = 0; i < oldVals.length; i++)
                    valArray[i] = oldVals[i];
                valArray[oldVals.length] = val;
            } else {
                valArray = new String[1];
                valArray[0] = val;
            }
            ht.put(key, valArray);
        }
        return ht;
    }

    /**
     * 将REQUEST的参数转化为可用的多层次的MAP
     * @param request
     * @return
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Object> getRequestMap(HttpServletRequest request) {
        Map<String, Object> map = new HashMap<String, Object>();
        Enumeration<String> names = request.getParameterNames();
        String name;
        while (names.hasMoreElements()) {
            name = names.nextElement();
            String value = request.getParameter(name);
            resolve(map, name, value);
        }
        return map;
    }

    public static void resolve(Map map,String key,String value){
    	String nowkey = key;
    	String childKey = "";
    	if(key.indexOf(".")>0){
    		nowkey = key.substring(0,key.indexOf("."));
    		childKey = key.substring(key.indexOf(".")+1);
    	}
    	if(Pattern.matches("\\w*\\[\\d]", nowkey)){//带有[0]等表示是个list
    		resolveList(map, nowkey,childKey, value);
    	}else{
    		resolveMap(map, nowkey,childKey, value);
    	}
    }
    
    public static void resolveMap(Map map,String key,String childKey,String value){
    	if(net.esj.basic.utils.StringUtils.hasText(childKey)){
    		Map childMap ;
    		if(map.containsKey(key)){
    			childMap = (Map) map.get(key);
    		}else{
    			childMap  = new HashMap();
    			map.put(key, childMap);
    		}
    		resolve(map, childKey, value);
    	}else{
    		map.put(key, value);
    	}
    }
    
    public static void resolveList(Map map,String key,String childKey,String value){
    	String[] tmps = key.split("\\[");
    	String nowkey = tmps[0];
    	int idx = Integer.valueOf(tmps[1].replace("]", ""));
    	
		List childList ;
		Map childMap = null;
		if(map.containsKey(nowkey)){
			childList = (List) map.get(nowkey);
			childMap = (Map) childList.get(idx);
		}else{
			childList  = new ArrayList();
			map.put(nowkey, childList);
		}
		if(childMap==null){
			childMap = new HashMap();
		}
		resolve(childMap,childKey, value);
		int i = childList.size()-1;
		while(idx>i){
			childList.add(null);
			i++;
		}
		childList.set(idx,childMap);
    }
    
    /**
     * 获取访问者IP
     * 
     * 在一般情况下使用Request.getRemoteAddr()即可，但是经过nginx等反向代理软件后，这个方法会失效。
     * 
     * 本方法先从Header中获取X-Real-IP，如果不存在再从X-Forwarded-For获得第一个IP(用,分割)，
     * 如果还不存在则调用Request .getRemoteAddr()。
     * 
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("X-Real-IP");
        if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        } else {
            return ip;
        }
        if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        } else {
            // 多次反向代理后会有多个IP值，第一个为真实IP。
            int index = ip.indexOf(',');
            if (index != -1) {
                ip = ip.substring(0, index);
            }
        }
        return ip;
    }

    public static boolean checkNotModified(HttpServletRequest request,
                                           HttpServletResponse response, long lastModifiedTimestamp) {
        boolean notModified = false;
        if (lastModifiedTimestamp >= 0
            && (response == null || !response.containsHeader(HEADER_LAST_MODIFIED))) {
            long ifModifiedSince = 0;
            try{
            	//apusic系统会有导常： java.lang.IllegalArgumentException: Bad date format: Thu, 01 Jan 1970 00:00:00 GMT
            	ifModifiedSince = request.getDateHeader(HEADER_IF_MODIFIED_SINCE);
            }catch (Exception e) {
				// ignore
			}
            notModified = (ifModifiedSince >= (lastModifiedTimestamp / 1000 * 1000));
            if (response != null) {
                if (notModified && "GET".equals(request.getMethod())) {
                    response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                } else {
                    response.setDateHeader(HEADER_LAST_MODIFIED, lastModifiedTimestamp);
                }
            }
        }
        return notModified;
    }
    
    public static Cookie getCookie(HttpServletRequest reqest,String name) {
        Cookie[] cookies = reqest.getCookies();
        if (cookies != null) {
            for (Cookie c : cookies) {
                if (c.getName().equals(name)) {
                    return c;
                }
            }
        }
        return null;
    }
    
    public void addCookie(HttpServletResponse response,Cookie cookie) {
        response.addCookie(cookie);
    }

    /**
     * 获得当的访问路径
     * 
     * HttpServletRequest.getRequestURL+"?"+HttpServletRequest.getQueryString
     * 
     * @param request
     * @return
     */
    public static String getLocation(HttpServletRequest request) {
        StringBuffer sb = request.getRequestURL();
        if (request.getQueryString() != null) {
            sb.append("?").append(request.getQueryString());
        }
        return sb.toString();
    }

    /**
     * 去掉后缀和contextPath的URI
     * @param req
     * @return
     */
    public static String getURIWithoutSuffixAndContextPath(HttpServletRequest req){
    	String url = req.getRequestURI();
        String context = req.getContextPath();
        if (url.indexOf(".") != -1) {
            return url.substring(context.length(), url.indexOf("."));
        } else if (url.indexOf("?") != -1) {
            return url.substring(context.length(), url.indexOf("?"));
        } else {
            return url.substring(context.length());
        }
    }
    
    /**
     * 去掉contextPath的URI
     * @param req
     * @return
     */
    public static String getURIWithoutContextPath(HttpServletRequest req){
    	String url = req.getRequestURI();
    	String context = req.getContextPath();
    	return url.substring(context.length());
    }
    
    public static void main(String[] args){
    	System.out.println(Pattern.matches("\\w*\\[\\d]", "discount[0]"));
    }
}
